/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package FEMSolver;

import BounderyPack.DBoundery;
import BounderyPack.DirihletPair;
import HashMatrix2.HashMatrix2;
import MathLib.triangulation.SaveStructures.Node;
import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import syntaxanalyser.PostfiksXY;

/**
 *
 * @author mark_o
 */
public class GradientMethod {
    protected ArrayList<DBoundery> NapivNodeList;
    protected ArrayList<Node> AllNodeList;
    double[] b;
    HashMatrix2 A;
    double eps=0.001;
    double rho=0.5;

    private DirihletPair[] mas;
    public OutputStream outPath = System.out;
    private double H=5;

    public GradientMethod(ArrayList<DBoundery> NapivNodeList, double[] b, HashMatrix2 A, DirihletPair[] mas) {
        this.NapivNodeList = NapivNodeList;
        this.b = b;
        this.A = A;
        this.mas = mas;
    }

    




    public double[] calc(){
        double[] u0 = new double[b.length];

        for (int i = 0; i < u0.length; i++) {
            u0[i] = 1;
        }

        while (true) {
            double[] u1 = new double[u0.length];

            for (int i = 0; i < u1.length; i++) {
                double tmpVal = 0.0;
                //ArrayList<Double> valList = A.getJRowValues(i);
                //ArrayList<Integer> posList = A.getJRowIndex(i);
                //for (int j = 0; j < posList.size(); j++) {
                //    tmpVal+=valList.get(j)*u0[posList.get(j)];
                //}
                for (int j = 0; j < b.length;j++) {
                    tmpVal+=A.getValue(i, j)*u0[j];
                }

                tmpVal+=P(u0,i)-b[i];
                tmpVal*=rho;
                u1[i] = u0[i]-tmpVal;
            }



            if (check(u0, u1)) {
                u0=u1;
                break;
            }
            u0=u1;
        }


        //print result to file

        PrintWriter pw =  null;
        try {
            pw = new PrintWriter(new BufferedOutputStream((outPath)));
            pw.println(u0.length + mas.length);
        if(mas.length>0){
            int j;
            for (j = 0; j < mas[0].getNodeNumber(); j++) {
                pw.println(u0[j]);
            }

            for(int i=0; i<mas.length-1; i++){
                int k=0;
                pw.println(mas[i].getValue());
                while(mas[i+1].getNodeNumber() - mas[i].getNodeNumber()-k!=1){
                    pw.println(u0[j]);
                    j++;
                    k++;
                }
            }

            pw.println(mas[mas.length-1].getValue());

            for (int i = j; i < u0.length; i++) {
                pw.println(u0[i]);
            }
        }else{
            for (int i = 0; i < u0.length; i++) {
                pw.println(u0[i]);
            }
        }

        } catch (Exception ex) {
            Logger.getLogger(MyPenaltyIteration.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
            pw.close();
        }




        return u0;
    }

    private boolean check(double[] prev, double[] next){
        boolean key = true;
        for(int i=0;i<prev.length;i++){
            if(Math.abs(prev[i]-next[i])>eps){
                key = false;
                System.out.print("перевірка:\t");
                System.out.println(i+"\t"+Math.abs(prev[i]-next[i]));
                break;
            }
        }
        return key;
    }

    private double P(double[] u0,int i) {
        for (int j = 0; j < NapivNodeList.size(); j++) {
            DBoundery boundery = NapivNodeList.get(j);
            if(boundery.contains(i)){
                //return Math.max(PostfiksXY.Calculate(boundery.getParams().h, AllNodeList.get(i).x, AllNodeList.get(i).x)-u0[i], 0);////////////////////////////////////////////////////////////////
                return Math.max(H-u0[i], 0)/eps;////////////////////////////////////////////////////////////////
            }
        }
        return 0;
    }
}
